package com.unionpay.acp.sdk;

import cn.demoncat.util.exception.BizRuntimeException;
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;

/**
 * 报文加密解密等操作的工具类
 * 
 * @author 银联
 *
 * @since 2016-7-22
 */
public class SecureUtil {
	/**
	 * 算法常量： SHA256
	 */
	private static final String ALGORITHM_SHA256 = "SHA-256";
	/**
	 * 算法常量：SHA256withRSA
	 */
	private static final String BC_PROV_ALGORITHM_SHA256RSA = "SHA256withRSA";

	
	/**
	 * sha256计算后进行16进制转换
	 * 
	 * @param data
	 *            待计算的数据
	 * @param encoding
	 *            编码
	 * @return 计算结果
	 */
	public static byte[] sha256X16(String data, String encoding) {
		byte[] bytes = sha256(data, encoding);
		StringBuilder sha256StrBuff = new StringBuilder();
		for (byte aByte : bytes) {
			if (Integer.toHexString(0xFF & aByte).length() == 1) {
				sha256StrBuff.append("0").append(Integer.toHexString(0xFF & aByte));
			} else {
				sha256StrBuff.append(Integer.toHexString(0xFF & aByte));
			}
		}
		try {
			return sha256StrBuff.toString().getBytes(encoding);
		} catch (UnsupportedEncodingException e) {
			throw buildException(e);
		}
	}
	
	/**
	 * sha256计算
	 * 
	 * @param data
	 *            待计算的数据
	 * @return 计算结果
	 */
	private static byte[] sha256(byte[] data) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance(ALGORITHM_SHA256);
			md.reset();
			md.update(data);
			return md.digest();
		} catch (Exception e) {
			throw buildException(e);
		}
	}
	
	/**
	 * sha256计算
	 * 
	 * @param datas
	 *            待计算的数据
	 * @param encoding
	 *            字符集编码
	 * @return
	 */
	private static byte[] sha256(String datas, String encoding) {
		try {
			return sha256(datas.getBytes(encoding));
		} catch (UnsupportedEncodingException e) {
			throw buildException(e);
		}
	}

	/**
	 * 签名
	 * 
	 * @param privateKey
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static byte[] signBySoft256(PrivateKey privateKey, byte[] data) throws Exception {
		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
		st.initSign(privateKey);
		st.update(data);
		return st.sign();
	}

	/**
	 * 验签
	 * 
	 * @param publicKey
	 * @param signData
	 * @param srcData
	 * @return
	 * 
	 * @author 延晓磊
	 * @throw Exception 
	 *
	 * @since 2020年4月1日
	 */
	public static boolean validateSignBySoft256(PublicKey publicKey, byte[] signData, byte[] srcData) throws Exception {
		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
		st.initVerify(publicKey);
		st.update(srcData);
		return st.verify(signData);
	}


	/**
	 * BASE64解码
	 * 
	 * @param inputByte
	 *            待解码数据
	 * @return 解码后的数据
	 * @throws IOException
	 */
	public static byte[] base64Decode(byte[] inputByte) {
		return Base64.decodeBase64(inputByte);
	}

	/**
	 * BASE64编码
	 * 
	 * @param inputByte
	 *            待编码数据
	 * @return 解码后的数据
	 * @throws IOException
	 */
	public static byte[] base64Encode(byte[] inputByte) {
		return Base64.encodeBase64(inputByte);
	}

	
	/**
	 * 构建异常
	 * 
	 * @param e
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月26日
	 */
	private static BizRuntimeException buildException(Exception e) {
		return new BizRuntimeException("签名支付参数失败", e);
	}
}
